import datetime
import json
import logging
from decimal import Decimal

from base.connection import redis_util
from base.request import ApiBaseHandler
from common.definition import OrderStatus, OrderType, PayStatus, PayType, ret_msg
from conf import config
from conf.config import DOMAIN
from daemon import tasks
from helper.api_helper import get_command
from helper.beanstalkd import add_mq_task
from helper.payment.pay_util import generator_trade_no
from helper.payment.wechat_pay import md5
from helper.register_help import register
from helper.user import AddressHelper, UserHelper
from util.json_util import JSONEncoder

logger = logging.getLogger("wechat.handlers.gift")


class CodeCheck(ApiBaseHandler):
    async def post(self):
        gift_code = str(self.get_parameter("code", 0))  # 口令
        serial_id = self.get_parameter("serial_id", None)  # 卡号
        gift_key = self.get_parameter("key", None)  # 校验码
        base_num = 99999  # 口令处理基数
        pre_code = int(gift_code[:-1])  # 实际口令
        agency_id = base_num - pre_code
        real_code = get_command(agency_id)
        if real_code != gift_code:
            return self.write(ret_msg(code=-1, error_message="口令错误，请重新输入！"))

        if not serial_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数卡号！"))

        if not gift_key:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数校验码！"))

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )
        agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
        if not agency or not gift_code:
            session.close()
            return self.write(ret_msg(code=-1, error_message="口令错误，请重新输入！"))

        code_str = f"{config.FACTORY_UID}{serial_id}"
        sign = md5(code_str.encode()).upper()
        if gift_key != sign:
            session.close()
            return self.write(ret_msg(code=-1, error_message="校验码无效！"))

        logger.info(f"agency_id={agency_id}")
        open_id = await self.get_open_id()
        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        parent_ua = session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
        if not parent_ua:
            session.close()
            logger.error(
                f"user_agency表无记录: agency_id={agency.ebf_agency_id}, open_id={open_id}"
            )
            return self.write(ret_msg(code=-1, error_message="礼品卡无效！"))

        uid = agency.ebf_agency_uid
        oid = parent_ua.ebf_ua_bind_user_id
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not ua:
            if user:
                parent_uid = user.ebf_user_agency_uid
                if parent_uid == config.DEFAULT_AGENCY_UID or not parent_uid:
                    parent_uid = uid
                    parent_id = agency_id
                else:
                    parent_agency = (
                        session.query(Agency)
                        .filter_by(ebf_agency_uid=parent_uid)
                        .first()
                    )
                    parent_id = parent_agency.ebf_agency_id if parent_agency else None
                recommend_user = user.ebf_user_recommend_user
                if recommend_user != oid:
                    user.ebf_user_recommend_user = oid
            else:
                logger.info(f"创建用户：open_id={open_id}, serial_id={serial_id}")
                await self.create_user(open_id, uid, oid)
                parent_uid = uid
                parent_id = agency_id
            password = md5("style999".encode())
            result = register(open_id, password, parent_id, parent_uid)
            if not result:
                logger.error(f"注册合伙人账号失败: open_id={open_id}, serial_id={serial_id}")
                session.close()
                return self.write(ret_msg(code=-1, error_message="系统繁忙，请稍后重试"))
            logger.info(f"注册合伙人账号成功: open_id={open_id}, serial_id={serial_id}")
        else:
            own_id = ua.ebf_agency_id
            own_agency = session.query(Agency).filter_by(ebf_agency_id=own_id).first()
            own_uid = own_agency.ebf_agency_uid if own_agency else None
            if user.ebf_user_agency_uid != own_uid and own_uid:
                user.ebf_user_agency_uid = own_uid
            recommend_user = user.ebf_user_recommend_user
            if recommend_user != oid:
                user.ebf_user_recommend_user = oid
        session.commit()
        session.close()
        return self.write(ret_msg())


class ReceiveGift(ApiBaseHandler):
    # 礼品卡领取礼品
    async def post(self):
        pattern = int(self.get_parameter("pattern", 0))  # 0=包邮到家 1=门店自提
        serial_id = self.get_parameter("serial_id", None)
        gift_key = self.get_parameter("key", None)
        store_id = int(self.get_parameter("store_id", 0))
        address_id = self.get_parameter("address_id", None)
        message = self.get_parameter("message", None)
        if pattern:
            if not store_id:
                return self.write(ret_msg(code=-1, error_message="请选择自提的门店"))
        else:
            if not address_id:
                return self.write(ret_msg(code=-1, error_message="请选择快递配送地址"))

        if not serial_id:
            return self.write(ret_msg(code=-1, error_message="缺少参数卡号"))

        if not gift_key:
            return self.write(ret_msg(code=-1, error_message="缺少参数校验码"))

        code_str = f"{config.FACTORY_UID}{serial_id}"
        sign = md5(code_str.encode()).upper()
        if gift_key != sign:
            return self.write(ret_msg(code=-1, error_message="校验码无效！"))

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        class GiftCard(object):
            pass

        class Order(object):
            pass

        class Goods(object):
            pass

        class StoreGoods(object):
            pass

        class Address(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
                {"db_table": "ebt_gift_card", "model": GiftCard},
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_store_goods", "model": StoreGoods},
                {"db_table": "sdet_address", "model": Address},
            ]
        )

        open_id = await self.get_open_id()
        qr = session.query(GiftCard).filter_by(id=serial_id).first()
        if not qr:
            session.close()
            return self.write(ret_msg(code=-1, error_message="礼品卡号错误"))

        qr_status = qr.status
        if qr_status == 0:
            return self.redirect(
                f"/static/giftcard/index.html#/activate?id={serial_id}&code={gift_key}"
            )
        elif qr_status == 2:
            return self.redirect(
                f"/static/giftcard/index.html#/nonvalid?id={serial_id}&code={gift_key}"
            )

        redis = redis_util.client
        flag = redis.get(f"gift_{open_id}_{serial_id}")
        if flag:
            session.close()
            return self.write(ret_msg(code=-1, error_message="不能重复请求"))
        else:
            redis.setex(f"gift_{open_id}_{serial_id}", 60, 1)
        # 绑定送礼人
        card_order_id = qr.gift_card_order_id
        card_order = session.query(Order).filter_by(sdef_order_id=card_order_id).first()
        invitor_oid = card_order.sdef_order_device_id
        invitor_ua = (
            session.query(UserAgency).filter_by(ebf_ua_bind_user_id=invitor_oid).first()
        )
        invitor_agency = (
            session.query(Agency)
            .filter_by(ebf_agency_id=invitor_ua.ebf_agency_id)
            .first()
        )
        invitor_uid = invitor_agency.ebf_agency_uid
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        logger.info(f"open_id={open_id}, invitor_uid={invitor_uid}")
        if ua:
            # 收礼人自己是合伙人
            agency = (
                session.query(Agency).filter_by(ebf_agency_id=ua.ebf_agency_id).first()
            )
            uid = agency.ebf_agency_uid
            if user.ebf_user_agency_uid != uid:
                user.ebf_user_agency_uid = uid
        else:
            if user:
                if (
                    user.ebf_user_agency_uid == config.DEFAULT_AGENCY_UID
                    or not user.ebf_user_agency_uid
                ):
                    user.ebf_user_agency_uid = invitor_uid
            else:
                user = await self.create_user(open_id, invitor_uid, invitor_oid)
        session.commit()

        if pattern:
            # 门店自提
            store = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
            if not store:
                session.close()
                return self.write(ret_msg(code=-1, error_message=f"门店{store_id}不存在！"))
            result, msg = self.create_order(
                open_id, pattern, message, serial_id, gift_key, store_id=store_id
            )
            # 8小时之后自动确认收货
            if result and not add_mq_task(msg, message_type=6, delay=8 * 3600):
                logger.error(f"8小时后自动确认收货加入任务队列失败：out_trade_no={msg}")
        else:
            # 包邮到家
            filters = dict(sdef_address_id=address_id, sdef_address_device_id=open_id)
            address = session.query(Address).filter_by(**filters).first()
            if not address:
                session.close()
                return self.write(
                    ret_msg(code=-1, error_message=f"地址编号{address_id}错误！")
                )
            result, msg = self.create_order(
                open_id, pattern, message, serial_id, gift_key, address_id=address_id
            )
            # 订单创建后解除使用地址锁定
            default_address = AddressHelper.get_default(open_id)
            use_address = AddressHelper.get_use(open_id)
            if use_address:
                if default_address:
                    if use_address["address_id"] != default_address["address_id"]:
                        is_default = True
                        is_use = True
                        AddressHelper.set_default(
                            open_id, default_address["address_id"], is_default, is_use
                        )
                else:
                    is_default = False
                    is_use = False
                    AddressHelper.set_default(
                        open_id, use_address["address_id"], is_default, is_use
                    )

        if not result:
            session.close()
            return self.write(ret_msg(code=-1, error_message=msg))
        # 触发支付成功异步任务
        tasks.order_paid.delay(msg)
        session.close()
        return self.write(ret_msg(data=msg))

    def create_order(
        self, oid, pattern, message, serial_id, gift_key, address_id=None, store_id=None
    ):
        class User(object):
            pass

        class Order(object):
            pass

        class Goods(object):
            pass

        class StoreGoods(object):
            pass

        class GiftCard(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_store_goods", "model": StoreGoods},
                {"db_table": "ebt_gift_card", "model": GiftCard},
            ]
        )

        ip = self.request.remote_ip
        user = session.query(User).filter_by(ebf_user_id=oid).first()
        qr = session.query(GiftCard).filter_by(id=serial_id).first()
        uid = user.ebf_user_agency_uid
        cart_goods = [{"id": "562897119687463", "count": 2}]  # V款2支
        cart_goods_array = []
        price_total = Decimal("0")
        if qr.status == 2:
            session.close()
            return False, "不能重复领取"

        for c in cart_goods:
            count = c["count"]
            goods_id = c["id"]
            if pattern:
                filters = dict(
                    sdef_goods_factory_uid=config.FACTORY_UID,
                    sdef_goods_store_id=store_id,
                    sdef_goods_id=goods_id,
                )
                goods = session.query(StoreGoods).filter_by(**filters).first()
            else:
                goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()
            goods_img = json.loads(goods.sdef_goods_thumbnail)[0]
            goods_price = goods.sdef_goods_price
            if goods.sdef_goods_count < count:
                session.close()
                msg = "商品库存不足"
                return False, msg
            goods.sdef_goods_count -= count
            goods = dict(
                id=goods_id,
                count=count,
                goods_img=goods_img,
                goods_name=goods.sdef_goods_name,
                goods_price=goods_price,
                goods_member_price=goods.sdef_goods_member_price,
                goods_pin_price=goods.sdef_goods_pin_price,
                balance_rate=goods.sdef_goods_balance_rate,
                rate=goods.sdef_goods_rate,
                master_rate=goods.sdef_goods_master_rate,
                invite_rate=goods.sdef_goods_invite_rate,
                invite_invite_rate=goods.sdef_goods_invite_invite_rate,
                career_rate=goods.sdef_goods_career_rate,
                invite_career_rate=goods.sdef_goods_invite_career_rate,
                supplier=goods.sdef_goods_supplier,
                goods_cost=goods.sdef_goods_cost,
            )
            price_total += goods_price * Decimal(count)
            cart_goods_array.append(goods)

        try:
            now = datetime.datetime.now()
            out_trade_no = generator_trade_no()
            goods_order = Order()
            goods_order.sdef_order_id = out_trade_no
            goods_order.sdef_order_factory_uid = config.FACTORY_UID
            goods_order.sdef_order_device_id = oid
            goods_order.sdef_order_fee = Decimal("0")
            goods_order.sdef_order_goods = json.dumps(cart_goods_array, cls=JSONEncoder)
            goods_order.sdef_order_balance_fee = price_total
            goods_order.sdef_order_name = "礼品订单"
            goods_order.sdef_order_message = message
            goods_order.sdef_order_status = OrderStatus.WAIT_EXPRESS
            goods_order.sdef_order_pay_status = PayStatus.SUCCESS
            goods_order.sdef_order_pay_time = now
            goods_order.sdef_order_pay_type = PayType.BALANCE
            goods_order.sdef_order_type = OrderType.NEW_GIFT
            goods_order.sdef_order_courier_phone = serial_id
            goods_order.sdef_order_courier_name = gift_key
            goods_order.sdef_order_ip = ip
            goods_order.sdef_order_delivery_fee = 0
            goods_order.sdef_order_create_time = now
            goods_order.sdef_order_agency_uid = uid
            goods_order.sdef_order_coupon_fee = Decimal("0")
            if pattern:
                goods_order.sdef_order_describe = "门店自提"
                goods_order.sdef_order_store_id = store_id
                goods_order.sdef_order_ship_type = 2
            else:
                goods_order.sdef_order_describe = "包邮到家"
                goods_order.sdef_order_address_id = address_id
            session.add(goods_order)

            # 更新礼品卡记录
            qr.status = 2
            qr.gift_order_id = out_trade_no
            qr.update_time = now
            session.commit()
            session.close()
        except Exception as e:
            logger.error(f"err={e}, open_id={oid}, ")
            session.rollback()
            session.close()
            return False, "领取失败，请重试"
        return True, out_trade_no


class PasswordCheck(ApiBaseHandler):
    async def post(self):
        open_id = await self.get_open_id()
        pwd = str(self.get_parameter("password", 0))  # 口令
        vip_id = self.get_parameter("vip_id", None)  # 卡号
        code = self.get_parameter("code", None)  # 校验码
        base_num = 99999  # 口令处理基数
        pre_pwd = int(pwd[:-1])  # 口令前五位数
        agency_id = base_num - pre_pwd
        real_pwd = get_command(agency_id)
        if real_pwd != pwd:
            return self.write(ret_msg(code=-1, error_message="口令错误，请重新输入！"))

        if not vip_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数卡号！"))

        if not code:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数校验码！"))

        class VipCard(object):
            pass

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_vip_card", "model": VipCard},
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )

        logger.info(f"agency_id={agency_id}, real_pwd={real_pwd}, pwd={pwd}")
        inviter_agency = (
            session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
        )
        if not inviter_agency:
            logger.error(f"agency表无记录: vip_id={vip_id} agency_id={agency_id}")
            session.close()
            return self.write(ret_msg(code=-1, error_message="口令错误，请重新输入！"))

        qr = session.query(VipCard).filter_by(id=vip_id).first()
        # 已激活员工卡跳转链接为vip商城
        url1 = f"/static/mall-2x/index.html#/mall?vip={vip_id}&code={code}"
        # 无效员工卡跳转链接
        url2 = f"/static/giftcard/index.html#/nonvalidVip?id={vip_id}&code={code}"
        # 扫码人与持卡人不一致跳转链接
        url3 = f"/static/giftcard/index.html#/differentVip?id={vip_id}&code={code}"
        if qr:
            status = qr.status
            oid = qr.open_id
            sign = qr.code
            if code != sign:
                logger.error(f"员工卡: {vip_id} 验证码 {code} 无效!")
                session.close()
                return self.redirect(url2)

            if status == 0:
                qr.status = 1
                qr.open_id = open_id
                qr.update_time = datetime.datetime.now()
            elif status == 1:
                if oid != open_id:
                    logger.info(
                        f"扫码人与持卡人不一致:oid={oid} open_id={open_id} vip_id={vip_id}"
                    )
                    session.close()
                    return self.redirect(url3)
                session.close()
                return self.redirect(url1)
            elif status == 2:
                session.close()
                return self.redirect(url2)
            else:
                logger.error(f"员工卡: {vip_id} 未知状态码: {status}")
                session.close()
                return self.redirect("/404")
        else:
            logger.error(f"员工卡: {vip_id} 不存在!")
            session.close()
            return self.redirect("/404")

        inviter_uid = inviter_agency.ebf_agency_uid
        inviter_ua = (
            session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
        )
        inviter_oid = inviter_ua.ebf_ua_bind_user_id
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        if not ua:
            if user:
                uid = user.ebf_user_agency_uid
                if not uid or uid == config.DEFAULT_AGENCY_UID:
                    user.ebf_user_agency_uid = inviter_uid
            else:
                await self.create_user(open_id, inviter_uid, inviter_oid)
        else:
            agency = (
                session.query(Agency).filter_by(ebf_agency_id=ua.ebf_agency_id).first()
            )
            agency_uid = agency.ebf_agency_uid
            if user.ebf_user_agency_uid != agency_uid:
                user.ebf_user_agency_uid = agency_uid

        self.update_user_level(open_id)
        session.commit()
        session.close()
        return self.write(ret_msg())

    def update_user_level(self, open_id):
        class User(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
            ]
        )

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        level = user.ebf_user_level
        if not level or level == 1:
            user.ebf_user_level = 10
            session.commit()

        session.close()
        return True


class GiftInfoHandler(ApiBaseHandler):
    # 送礼信息处理
    async def post(self):
        open_id = await self.get_open_id()
        msg = str(self.get_parameter("message", ""))
        img_url = str(self.get_parameter("img_url", ""))

        store_id = self.get_parameter("store_id", None)
        if store_id:
            store_id = int(store_id)
        else:
            store_id = 1

        class GiftInfo(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_gift_info", "model": GiftInfo},
            ]
        )

        now = datetime.datetime.now()

        g = GiftInfo()
        g.sender = open_id
        g.message = msg
        g.img = img_url
        g.status = 0
        g.recommend_store_id = store_id
        g.create_time = now
        g.update_time = now

        session.add(g)
        session.flush()

        serial_id = g.id
        code = md5(f"{config.FACTORY_UID}{serial_id}".encode()).upper()
        g.code = code
        session.commit()
        session.close()

        data = {
            "serial_id": serial_id,
            "key": code,
        }
        return self.write(ret_msg(data=data))

    async def get(self):
        """
        获取送礼信息
        order_id: 送礼订单编号
        code: 密码
        """
        open_id = await self.get_open_id()
        order_id = self.get_parameter("order_id", None)
        code = self.get_parameter("code", None)

        if not code:
            code = self.get_parameter("key", None)

        class GiftInfo(object):
            pass

        class Order(object):
            pass

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_gift_info", "model": GiftInfo},
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )

        g = session.query(GiftInfo).filter_by(gift_sender_order_id=order_id).first()
        o = session.query(Order).filter_by(sdef_order_id=order_id).first()

        if not g:
            logger.error(f"送礼记录不存在 order_id={order_id} code={code}")
            return self.write(ret_msg(-1, error_message="送礼记录不存在！"))

        if code != g.code and open_id != g.sender:
            logger.error(f"order_id={order_id} code={code} saved_code={g.code}")
            return self.write(ret_msg(-1, error_message="密钥错误！"))

        cart_goods = json.loads(o.sdef_order_goods)
        gift_goods_array = []
        for c in cart_goods:
            goods_id = c["id"]
            goods_count = c["count"]
            gift_goods_array.append({"id": goods_id, "count": goods_count})

        data = {
            "order_id": order_id,
            "code": g.code,
            "status": g.status,
            "sender": g.sender,
            "message": g.message,
            "img_url": g.img,
            "store_id": g.recommend_store_id,
            "goods": gift_goods_array,
        }
        session.close()
        return self.write(ret_msg(data=data))


class ReceiveGiftHandler(ApiBaseHandler):
    # 送礼订单领取礼品
    async def post(self):
        pattern = int(self.get_parameter("pattern", 0))  # 0=包邮到家 1=门店自提
        order_id = self.get_parameter("order_id", None)
        gift_key = self.get_parameter("key", None)
        store_id = int(self.get_parameter("store_id", 0))
        address_id = self.get_parameter("address_id", None)
        message = self.get_parameter("message", None)

        if pattern:
            if not store_id:
                return self.write(ret_msg(code=-1, error_message="请选择自提的门店"))
        else:
            if not address_id:
                return self.write(ret_msg(code=-1, error_message="请选择快递配送地址"))

        if not order_id:
            return self.write(ret_msg(code=-1, error_message="缺少参数卡号/订单号"))

        if not gift_key:
            return self.write(ret_msg(code=-1, error_message="缺少参数校验码"))

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        class GiftInfo(object):
            pass

        class Order(object):
            pass

        class Goods(object):
            pass

        class StoreGoods(object):
            pass

        class Address(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
                {"db_table": "ebt_gift_info", "model": GiftInfo},
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_store_goods", "model": StoreGoods},
                {"db_table": "sdet_address", "model": Address},
            ]
        )

        open_id = await self.get_open_id()
        gift = session.query(GiftInfo).filter_by(gift_sender_order_id=order_id).first()
        if not gift:
            session.close()
            return self.write(ret_msg(code=-1, error_message="礼品订单号错误"))

        if gift_key != gift.code:
            session.close()
            return self.write(ret_msg(code=-1, error_message="校验码无效！"))

        gift_status = gift.status
        if gift_status == 0:
            session.close()
            logger.error(
                f"领取礼品：礼品订单失效 status={gift_status} open_id={open_id} order_id={order_id}"
            )
            return self.write(
                ret_msg(code=-1, error_message=f"礼品订单未支付 status={gift_status}")
            )
        elif gift_status == 2:
            logger.error(
                f"领取礼品：礼品已经被领取 status={gift_status} open_id={open_id} order_id={order_id}"
            )
            session.close()
            return self.write(
                ret_msg(code=2, error_message=f"礼品订单礼品已经被领取 status={gift_status}")
            )
        elif gift_status != 1:
            session.close()
            logger.error(
                f"领取礼品：礼品订单失效 status={gift_status} open_id={open_id} order_id={order_id}"
            )
            return self.write(
                ret_msg(code=-1, error_message=f"礼品订单失效 status={gift_status}")
            )

        redis = redis_util.client
        flag = redis.get(f"gift_{open_id}_{order_id}")
        if flag:
            logger.error(
                f"领取礼品：不能重复请求 open_id={open_id} order_id={order_id} key={gift_key}"
            )
            session.close()
            return self.write(ret_msg(code=-1, error_message="不能重复请求"))
        else:
            redis.setex(f"gift_{open_id}_{order_id}", 60, 1)
        # 绑定送礼人
        invitor_oid = gift.sender
        invitor_uid = UserHelper.get_user_agency_uid(invitor_oid)
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        logger.info(f"领取礼品：open_id={open_id}, invitor_uid={invitor_uid}")
        if ua:
            # 收礼人自己是合伙人
            agency = (
                session.query(Agency).filter_by(ebf_agency_id=ua.ebf_agency_id).first()
            )
            uid = agency.ebf_agency_uid
            if user.ebf_user_agency_uid != uid:
                user.ebf_user_agency_uid = uid
            user.ebf_user_recommend_user = invitor_oid  # 更新推荐人
        else:
            if user:
                if (
                    user.ebf_user_agency_uid == config.DEFAULT_AGENCY_UID
                    or not user.ebf_user_agency_uid
                ):
                    user.ebf_user_agency_uid = invitor_uid  # 绑定送礼人
                    user.ebf_user_recommend_user = invitor_oid  # 更新推荐人
            else:
                user = await self.create_user(open_id, invitor_uid, invitor_oid)
        session.commit()

        if pattern:
            # 门店自提
            store = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
            if not store:
                session.close()
                return self.write(ret_msg(code=-1, error_message=f"门店{store_id}不存在！"))
            result, msg = self.create_order(
                open_id, pattern, message, order_id, gift_key, store_id=store_id
            )
            # 8小时之后自动确认收货
            if result and not add_mq_task(msg, message_type=6, delay=8 * 3600):
                logger.error(f"领取礼品：8小时后自动确认收货加入任务队列失败：out_trade_no={msg}")
        else:
            # 包邮到家
            filters = dict(sdef_address_id=address_id, sdef_address_device_id=open_id)
            address = session.query(Address).filter_by(**filters).first()
            if not address:
                session.close()
                return self.write(
                    ret_msg(code=-1, error_message=f"地址编号{address_id}错误！")
                )
            result, msg = self.create_order(
                open_id, pattern, message, order_id, gift_key, address_id=address_id
            )
            # 订单创建后解除使用地址锁定
            default_address = AddressHelper.get_default(open_id)
            use_address = AddressHelper.get_use(open_id)
            if use_address:
                if default_address:
                    if use_address["address_id"] != default_address["address_id"]:
                        is_default = True
                        is_use = True
                        AddressHelper.set_default(
                            open_id, default_address["address_id"], is_default, is_use
                        )
                else:
                    is_default = False
                    is_use = False
                    AddressHelper.set_default(
                        open_id, use_address["address_id"], is_default, is_use
                    )

        if not result:
            session.close()
            logger.error(f"领取礼品：error={msg} open_id={open_id} order_id={order_id}")
            return self.write(ret_msg(code=-1, error_message=msg))
        # 触发支付成功异步任务
        # tasks.order_paid.delay(msg)
        session.close()
        return self.write(ret_msg(data=msg))

    def create_order(
        self,
        open_id,
        pattern,
        message,
        order_id,
        gift_key,
        address_id=None,
        store_id=None,
    ):
        class User(object):
            pass

        class Order(object):
            pass

        class Goods(object):
            pass

        class StoreGoods(object):
            pass

        class GiftInfo(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "sdet_order", "model": Order},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_store_goods", "model": StoreGoods},
                {"db_table": "ebt_gift_info", "model": GiftInfo},
            ]
        )

        ip = self.request.remote_ip
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        gift = session.query(GiftInfo).filter_by(gift_sender_order_id=order_id).first()
        o = session.query(Order).filter_by(sdef_order_id=order_id).first()
        uid = user.ebf_user_agency_uid
        cart_goods = json.loads(o.sdef_order_goods)
        cart_goods_array = []
        price_total = Decimal("0")
        if gift.status == 2:
            session.close()
            return False, "领取礼品: 不能重复领取"

        for c in cart_goods:
            count = c["count"]
            goods_id = c["id"]
            if pattern:
                filters = dict(
                    sdef_goods_factory_uid=config.FACTORY_UID,
                    sdef_goods_store_id=store_id,
                    sdef_goods_id=goods_id,
                )
                goods = session.query(StoreGoods).filter_by(**filters).first()
            else:
                goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()
            goods_img = json.loads(goods.sdef_goods_thumbnail)[0]
            goods_price = goods.sdef_goods_price
            if goods.sdef_goods_count < count:
                session.close()
                msg = "商品库存不足"
                return False, msg
            goods.sdef_goods_count -= count
            goods = dict(
                id=goods_id,
                count=count,
                goods_img=goods_img,
                goods_name=goods.sdef_goods_name,
                goods_price=goods_price,
                goods_member_price=goods.sdef_goods_member_price,
                goods_pin_price=goods.sdef_goods_pin_price,
                balance_rate=goods.sdef_goods_balance_rate,
                rate=goods.sdef_goods_rate,
                master_rate=goods.sdef_goods_master_rate,
                invite_rate=goods.sdef_goods_invite_rate,
                invite_invite_rate=goods.sdef_goods_invite_invite_rate,
                career_rate=goods.sdef_goods_career_rate,
                invite_career_rate=goods.sdef_goods_invite_career_rate,
                supplier=goods.sdef_goods_supplier,
                goods_cost=goods.sdef_goods_cost,
            )
            price_total += goods_price * Decimal(count)
            cart_goods_array.append(goods)

        try:
            now = datetime.datetime.now()
            out_trade_no = generator_trade_no()
            goods_order = Order()
            goods_order.sdef_order_id = out_trade_no
            goods_order.sdef_order_factory_uid = config.FACTORY_UID
            goods_order.sdef_order_device_id = open_id
            goods_order.sdef_order_fee = Decimal("0")
            goods_order.sdef_order_goods = json.dumps(cart_goods_array, cls=JSONEncoder)
            goods_order.sdef_order_balance_fee = Decimal("0")
            goods_order.sdef_order_name = "礼品订单"
            goods_order.sdef_order_message = message
            goods_order.sdef_order_status = OrderStatus.WAIT_EXPRESS
            goods_order.sdef_order_pay_status = PayStatus.SUCCESS
            goods_order.sdef_order_pay_time = now
            goods_order.sdef_order_pay_type = PayType.COUPON
            goods_order.sdef_order_type = OrderType.NEW_GIFT
            goods_order.sdef_order_courier_phone = order_id  # sender_order_id
            goods_order.sdef_order_courier_name = (
                o.sdef_order_device_id
            )  # sender_open_id
            goods_order.sdef_order_ip = ip
            goods_order.sdef_order_delivery_fee = 0
            goods_order.sdef_order_create_time = now
            goods_order.sdef_order_agency_uid = uid
            goods_order.sdef_order_coupon_fee = price_total
            if goods_order.sdef_order_remarks:
                goods_order.sdef_order_remarks += f"\n送礼订单={order_id}"
            else:
                goods_order.sdef_order_remarks = f"送礼订单={order_id}"
            if pattern:
                goods_order.sdef_order_describe = "门店自提"
                goods_order.sdef_order_store_id = store_id
                goods_order.sdef_order_ship_type = 2
            else:
                goods_order.sdef_order_describe = "包邮到家"
                goods_order.sdef_order_address_id = address_id
            session.add(goods_order)

            # 更新礼品卡记录
            gift.status = 2
            gift.receiver = open_id
            gift.gift_receiver_order_id = out_trade_no
            gift.update_time = now
            o.sdef_order_status = OrderStatus.COMPLETE
            if o.sdef_order_remarks:
                o.sdef_order_remarks += f"\n收礼人={open_id} 收礼订单={out_trade_no}"
            else:
                o.sdef_order_remarks = f"\n收礼人={open_id} 收礼订单={out_trade_no}"

            # 通知送礼人
            try:
                touser = o.sdef_order_device_id
                total_amount = price_total
                store_id = 0
                order_type = OrderType.GIFT_CARD
                nickname = (
                    user.ebf_user_nickname if user.ebf_user_nickname != "未关注" else ""
                )
                first = f"您送出的礼物已经被朋友{nickname}领取。"
                remark = f"我们将根据您朋友的收礼订单{out_trade_no}及时发货。"
                tasks.send_order_pay_success_notice.delay(
                    touser, order_id, total_amount, store_id, order_type, first, remark
                )
                logger.info(f"领取礼品: 通知送礼人成功 order_id={order_id} user={touser}")
            except Exception as e:
                logger.exception(e)
                logger.error(f"领取礼品: 通知送礼人失败 order_id={order_id} user={touser}")

            # 通知收礼人
            try:
                touser = open_id
                total_amount = price_total
                store_id = 0
                order_type = OrderType.NEW_GIFT
                sender = UserHelper.get_user(o.sdef_order_device_id)
                nickname = (
                    sender.ebf_user_nickname
                    if sender.ebf_user_nickname != "未关注"
                    else ""
                )
                first = f"感谢您领取您的朋友{nickname}送出的礼物。"
                remark = f"您的收礼订单{out_trade_no}待发货。我们将及时发货，发货后可以到个人中心查看订单物流状态。"
                tasks.send_order_pay_success_notice.delay(
                    touser,
                    out_trade_no,
                    total_amount,
                    store_id,
                    order_type,
                    first,
                    remark,
                )
                logger.info(f"领取礼品: 通知收礼人成功 order_id={out_trade_no} user={touser}")
            except Exception as e:
                logger.exception(e)
                logger.error(f"领取礼品: 通知收礼人失败 order_id={out_trade_no} user={touser}")

            session.commit()
            session.close()
        except Exception as e:
            logger.error(
                f"领取礼品: 错误 exception={e}, open_id={open_id}, order_id={order_id}"
            )
            session.rollback()
            session.close()
            return False, "领取失败，请重试"
        return True, out_trade_no


class GiftApplication(ApiBaseHandler):
    """
    领取礼品-发送申领成功通知
    https://wx.laez9.com/api/gift/application
    """

    async def get(self):
        open_id = await self.get_open_id()
        logger.info(f"GiftApplication: open_id={open_id}")
        try:
            tasks.send_gift_application_notice.delay(open_id)
            return self.write(ret_msg())
        except Exception as e:
            logger.error(f"领取礼品: 发送申领成功通知失败 open_id={open_id} exception={e}")
            return self.write(ret_msg(code=-1, error_message="发送申领成功通知失败"))
